-
Notifications
You must be signed in to change notification settings - Fork 24.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Android: Enable views to be nested within <Text> #8619
Conversation
627c331
to
5b50a0e
Compare
This is a lot, I'll look tomorrow (Friday) |
I'm looking through this. It might actually be better to have this as separate PRs. When we import them, all the commits get squashed into one request. Would probably be easier to get through. |
@@ -348,6 +355,15 @@ public ReactTextShadowNode(boolean isVirtual) { | |||
} | |||
} | |||
|
|||
// Returns a line height which takes into account the requested line height | |||
// and the height of the inline images. | |||
public float getAffectiveLineHeight() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should be effectiveLineHeight
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
The first commit seems good (modulo the one thing inline) |
The second commit is solid. Nice refactoring. |
Ditto for third. |
@dmmiller I haven't seen any updates in a few days. Are you still reviewing this or are you waiting for me to take some action? |
@rigdern Sorry, was on holiday last week. I thought I noted that here, but I didn't. I have looked at the first three commits. I'd actually prefer them to go in separately because we actually squash any PR into one commit so we would end up with a giant one. They seem independent and good cleanup and I can quickly stamp them since I've already looked at them. Then you can rebase the fourth and just that one can be looked at in more detail. Again sorry for the delay, I thought I had mentioned I was on holiday but forgot. |
5b50a0e
to
e96c15a
Compare
@dmmiller Okay, here's what I did. I addressed your feedback, rebased all of my commits onto the latest master, and tested the changes. Then I split this into 2 other PRs:
This PR still includes the other 3 commits (because it builds on them) but it has been rebased onto the latest master. You can review the last commit (Enable views to be nested within ). After the other PRs are accepted, I will rebase this on master and remove the other 3 commits from this PR. In addition to reviewing the last commit, a couple of other things still need to happen:
|
e96c15a
to
a49a4d9
Compare
Accepted those two PRs I don't know about css, @emilsjolander is the right person for that, and I assume you are working with him on the css PR. |
Yup, looking at merging css-layout end of this or early next week. |
…pport Summary: This PR was split from commits originally in #8619. /cc dmmiller These refactorings to the HierarchyOptimizer are in preparation for implementing support for inline views in #8619. **Refactoring 1: Collapse add*LayoutOnlyNodeToLayoutOnlyNode** addLayoutOnlyNodeToLayoutOnlyNode and addNonLayoutOnlyNodeToLayoutOnlyNode had nearly identical implementations. They both walk thru the ancestors looking for a nonlayout-only node and adjusting the passed in index at each step. This introduces a new function, walkUpUntilNonLayoutOnly, which takes care of that responsibility. This simplifies addNodeToNode because it can now consider the type of the parent and the type of the child independently. **Refactoring 2: Extract addGrandchildren** Pull out addLayoutOnlyNode's logic into a helper called addGrandchildren. We will need to call this method in another place later. **Test plan (required)** This change was tested with UIExplorer and a small test app and it's being used in my team's app. Closes #8908 Differential Revision: D3592783 Pulled By: dmmiller fbshipit-source-id: a513e8d381e71112ce6348bbee7d4a7c62c33619
Summary: This PR was split from a commit originally in #8619. /cc dmmiller When an inline image was larger than the specified line height, the image would be clipped. This changes the behavior so that the line height is changed to make room for the inline image. This is consistent with the behavior of RN for iOS. Here's how the change works. ReactTextView now receives its line height from the layout thread rather than directly from JavaScript. The reason is that the layout thread may pick a different line height. In the case that the tallest inline image is larger than the line height supplied by JavaScript, we want to use that image's height as the line height rather than the supplied line height. Also fixed a bug where the image, which is supposed to be baseline aligned, would be positioned at the wrong y location. To fix this, we use `y` (the baseline) in the `draw` method rather than trying to calculate the baseline from `bottom`. For more information see https://code.google.com/p/andro Closes #8907 Differential Revision: D3592781 Pulled By: dmmiller fbshipit-source-id: cba6cd86eb4e3abef6a0d7a81f802bdb0958492e
In order for this to work, we need to implement either option (2) custom Drawables or (3) inline views.
I can look into doing an implementation of inline views in which Text components which have inline views get wrapped by a View. That way, we won't have to make changes to the NativeViewHierarchyOptimizer and might be able to keep the changes contained to the Text component. @astreet, can you find somebody who can help give advice on the following problems (they might look familiar because they were mentioned earlier in this issue)?:
|
It's been a while since the last commit was reviewed and the labels show this pull request needs review. Based on the blame information for the files in this pull request we identified @emilsjolander as a potential reviewer. Could you take a look please or cc someone with more context? |
Sorry about the delay on this, I was out:
When we're talking about adding specifically image-rendering functionality that we don't think is necessarily useful or worth 'paying for' to the core library, custom Drawables doesn't seem bad to me. Currently, you would be able to create a custom ViewManager (a la https://github.com/facebook/react-native/blob/1926fdf156e077ad8b0c73505c6447d1a16687f8/ReactAndroid/src/main/java/com/facebook/react/views/text/frescosupport/FrescoBasedReactTextInlineImageViewManager.java) and extend ReactTextInlineImageShadowNode (see https://github.com/facebook/react-native/search?utf8=%E2%9C%93&q=ReactTextInlineImageShadowNode&type=Code) Given the difficulties you're listing (which I don't think are easily solvable), at this point I feel pretty confident that adding animated inline image support specifically is the right call here. |
…pport Summary: This PR was split from commits originally in facebook#8619. /cc dmmiller These refactorings to the HierarchyOptimizer are in preparation for implementing support for inline views in facebook#8619. **Refactoring 1: Collapse add*LayoutOnlyNodeToLayoutOnlyNode** addLayoutOnlyNodeToLayoutOnlyNode and addNonLayoutOnlyNodeToLayoutOnlyNode had nearly identical implementations. They both walk thru the ancestors looking for a nonlayout-only node and adjusting the passed in index at each step. This introduces a new function, walkUpUntilNonLayoutOnly, which takes care of that responsibility. This simplifies addNodeToNode because it can now consider the type of the parent and the type of the child independently. **Refactoring 2: Extract addGrandchildren** Pull out addLayoutOnlyNode's logic into a helper called addGrandchildren. We will need to call this method in another place later. **Test plan (required)** This change was tested with UIExplorer and a small test app and it's being used in my team's app. Closes facebook#8908 Differential Revision: D3592783 Pulled By: dmmiller fbshipit-source-id: a513e8d381e71112ce6348bbee7d4a7c62c33619
Summary: This PR was split from a commit originally in facebook#8619. /cc dmmiller When an inline image was larger than the specified line height, the image would be clipped. This changes the behavior so that the line height is changed to make room for the inline image. This is consistent with the behavior of RN for iOS. Here's how the change works. ReactTextView now receives its line height from the layout thread rather than directly from JavaScript. The reason is that the layout thread may pick a different line height. In the case that the tallest inline image is larger than the line height supplied by JavaScript, we want to use that image's height as the line height rather than the supplied line height. Also fixed a bug where the image, which is supposed to be baseline aligned, would be positioned at the wrong y location. To fix this, we use `y` (the baseline) in the `draw` method rather than trying to calculate the baseline from `bottom`. For more information see https://code.google.com/p/andro Closes facebook#8907 Differential Revision: D3592781 Pulled By: dmmiller fbshipit-source-id: cba6cd86eb4e3abef6a0d7a81f802bdb0958492e
…pport Summary: This PR was split from commits originally in facebook#8619. /cc dmmiller These refactorings to the HierarchyOptimizer are in preparation for implementing support for inline views in facebook#8619. **Refactoring 1: Collapse add*LayoutOnlyNodeToLayoutOnlyNode** addLayoutOnlyNodeToLayoutOnlyNode and addNonLayoutOnlyNodeToLayoutOnlyNode had nearly identical implementations. They both walk thru the ancestors looking for a nonlayout-only node and adjusting the passed in index at each step. This introduces a new function, walkUpUntilNonLayoutOnly, which takes care of that responsibility. This simplifies addNodeToNode because it can now consider the type of the parent and the type of the child independently. **Refactoring 2: Extract addGrandchildren** Pull out addLayoutOnlyNode's logic into a helper called addGrandchildren. We will need to call this method in another place later. **Test plan (required)** This change was tested with UIExplorer and a small test app and it's being used in my team's app. Closes facebook#8908 Differential Revision: D3592783 Pulled By: dmmiller fbshipit-source-id: a513e8d381e71112ce6348bbee7d4a7c62c33619
Summary: This PR was split from a commit originally in facebook#8619. /cc dmmiller When an inline image was larger than the specified line height, the image would be clipped. This changes the behavior so that the line height is changed to make room for the inline image. This is consistent with the behavior of RN for iOS. Here's how the change works. ReactTextView now receives its line height from the layout thread rather than directly from JavaScript. The reason is that the layout thread may pick a different line height. In the case that the tallest inline image is larger than the line height supplied by JavaScript, we want to use that image's height as the line height rather than the supplied line height. Also fixed a bug where the image, which is supposed to be baseline aligned, would be positioned at the wrong y location. To fix this, we use `y` (the baseline) in the `draw` method rather than trying to calculate the baseline from `bottom`. For more information see https://code.google.com/p/andro Closes facebook#8907 Differential Revision: D3592781 Pulled By: dmmiller fbshipit-source-id: cba6cd86eb4e3abef6a0d7a81f802bdb0958492e
c74001d
to
249ef50
Compare
@rigdern updated the pull request - view changes |
I accidentally pushed to this branch. There's nothing new to review yet. |
any update on this PR please? |
@huangmr: What are you trying to achieve? Would be good to know what other people are trying to do with this patch. |
@rigdern do you still plan to add more commits to this PR or is it ready for another review pass? |
@hramos, last time @astreet reviewed this, he expressed concerns with the current approach and suggested a couple of other approaches. Unless opinions have changed on my original approach, I have to try out one of the other approaches and update the PR before it can be reviewed. Because investigating the other approaches will be time consuming and the current implementation is working well for my team's app, I haven't had the chance to revisit this PR yet. |
It sounds like you might just never revisit this PR. Should we close it? |
@lacker I intend on coming back to this at some point. My team needs this feature and is currently using this PR in our app. We want this feature to be part of the official RN repo. Revisiting this PR will be time consuming so I can't justify spending time on it right now given the priorities of my other work. If you'd like, I can close the PR and repoen it or open a new one when I revisit it. What do you think? |
That sounds good. Let's open a new one when you revisit - I think that will just help us organizationally get a handle on our pull request backlog. Thanks for understanding! |
Summary: This PR was split from a commit originally in #8619. /cc dmmiller When an inline image was larger than the specified line height, the image would be clipped. This changes the behavior so that the line height is changed to make room for the inline image. This is consistent with the behavior of RN for iOS. Here's how the change works. ReactTextView now receives its line height from the layout thread rather than directly from JavaScript. The reason is that the layout thread may pick a different line height. In the case that the tallest inline image is larger than the line height supplied by JavaScript, we want to use that image's height as the line height rather than the supplied line height. Also fixed a bug where the image, which is supposed to be baseline aligned, would be positioned at the wrong y location. To fix this, we use `y` (the baseline) in the `draw` method rather than trying to calculate the baseline from `bottom`. For more information see https://code.google.com/p/andro Closes #8907 Differential Revision: D3592781 Pulled By: dmmiller
Summary: This PR was split from a commit originally in facebook#8619. /cc dmmiller When an inline image was larger than the specified line height, the image would be clipped. This changes the behavior so that the line height is changed to make room for the inline image. This is consistent with the behavior of RN for iOS. Here's how the change works. ReactTextView now receives its line height from the layout thread rather than directly from JavaScript. The reason is that the layout thread may pick a different line height. In the case that the tallest inline image is larger than the line height supplied by JavaScript, we want to use that image's height as the line height rather than the supplied line height. Also fixed a bug where the image, which is supposed to be baseline aligned, would be positioned at the wrong y location. To fix this, we use `y` (the baseline) in the `draw` method rather than trying to calculate the baseline from `bottom`. For more information see https://code.google.com/p/andro Closes facebook#8907 Differential Revision: D3592781 Pulled By: dmmiller
Potential breaking change: The signature of ReactShadowNode's onBeforeLayout method was changed
Depends on this css-layout PR:
facebook/yoga#202
Implements same feature as this iOS PR:
#7304
Previously, only Text and Image could be nested within Text. Now, any view can be nested within Text. One restriction of this feature is that developers must give inline views a width and a height via the style prop. Here's a screenshot illustrating this feature:
Note that the changes to NativeViewHierarchyOptimizer were broken up across a few commits to make the diffs easier to understand.
Previously, inline Images were supported via FrescoBasedReactTextInlineImageSpan. To get support for nesting views within Text, we create one special kind of span per inline view. This span is called TextInlineViewPlaceholderSpan. It is the same size as the inline view. Its job is just to occupy space -- it doesn't render any visual. After the text is rendered, we query the Android Layout object associated with the TextView to find out where it has positioned each TextInlineViewPlaceholderSpan. We then position the views to be at those locations.
One tricky aspect of the implementation is that the Text component needs to be able to render native children (the inline views) but the Android TextView cannot have children. This is solved by having the native parent of the ReactTextView also host the inline views. Implementation-wise, this was accomplished by extending the NativeViewHierarchyOptimizer to handle this case. The optimizer now handles these cases:
Limitation: Clipping
If Text's height/width is small such that an inline view doesn't completely fit, the inline view may still be fully visible due to hoisting (the inline view isn't actually parented to the Text which has the limited size. It is parented to an ancestor which may have a different clipping rectangle.). Prior to this change, layout-only views had a similar limitation.
Test plan (required)
This change was tested with UIExplorer and a small test app and it's being used in my team's app.
Outstanding Issue: Using Text and Image within an inline view
Currently, you cannot use Text or Image components within an inline view. This is because the React context flag,
isInAParentText
, indicates that you're still inside of a Text component and these components use their virtual node representation rather than their normal representation.The Text component sets
isInAParentText
totrue
. No components ever setisInAParentText
tofalse
.I need some help with fixing this. One option I was considering was setting
isInAParentText
tofalse
for all other native components. This could be done by editing the native component creation primitives such asrequireNativeComponent
andcreateReactNativeComponentClass
to provide the appropriate context. However, when I tried this, it didn’t work and it wasn’t clear to me whether or not context works on native components. Thoughts?Adam Comella
Microsoft Corp.